home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / wall / wall.c < prev    next >
C/C++ Source or Header  |  1992-04-22  |  10KB  |  451 lines

  1. /* 
  2.  * wall.c --
  3.  *
  4.  * Write to all.  Sends a message to the /dev/syslog window of
  5.  * each machine, or the local host if specified.
  6.  *
  7.  * Copyright 1989 Regents of the University of California
  8.  * Permission to use, copy, modify, and distribute this
  9.  * software and its documentation for any purpose and without
  10.  * fee is hereby granted, provided that the above copyright
  11.  * notice appear in all copies.  The University of California
  12.  * makes no representations about the suitability of this
  13.  * software for any purpose.  It is provided "as is" without
  14.  * express or implied warranty.
  15.  */
  16.  
  17. #ifndef lint
  18. static char rcsid[] = "$Header: /sprite/src/cmds/wall/RCS/wall.c,v 1.13 92/04/22 14:21:28 kupfer Exp $";
  19. #endif /* not lint */
  20.  
  21. #define NDEBUG
  22.  
  23. #include <sprite.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <fcntl.h>
  27. #include <mig.h>
  28. #include <host.h>
  29. #include <sys/time.h>
  30. #include <pwd.h>
  31. #include <option.h>
  32. #include <sys/signal.h>
  33. #include <sys/stat.h>
  34. #include <sys/wait.h>
  35. #include <errno.h>
  36. #include <rloginPseudoDev.h>
  37. #include <setjmp.h>
  38. #include <ulog.h>
  39.  
  40.  
  41. #define MAX_NUM_HOSTS   0x100
  42. #define MAX_MSG_LEN     0x400
  43. #define TIME_OUT        180
  44. #define HOST_NAME_SIZE  64
  45.  
  46. #ifdef __STDC__
  47. static void SendMsg(char *msg, int msize, char *host, int doRlogin);
  48. static void FillAlert(void);
  49. static void Down(int n);
  50. static void Prompt(void);
  51. #else
  52. static void SendMsg();
  53. static void FillAlert();
  54. static void Down();
  55. static void Prompt();
  56. #endif
  57.  
  58. static Mig_Info infoArray[MAX_NUM_HOSTS];
  59. static char buf[MAX_MSG_LEN];
  60. static int verbose = 0;
  61. static int debug = 0;
  62. static int local = 0;
  63. static int wallRlogins = 1;
  64. static int consoles = 1;
  65.  
  66. static char alert[0x100];
  67.  
  68. extern int errno;
  69.  
  70. Option optionArray[] = {
  71.     {OPT_TRUE, "l", (Address)&local,
  72.      "Run on local host only."},
  73.     {OPT_TRUE, "v", (Address)&verbose,
  74.      "Print as hosts are accessed."},
  75.     {OPT_TRUE, "d", (Address)&debug,
  76.      "Enable debugging."},
  77.     {OPT_FALSE, "r", (Address)&wallRlogins,
  78.      "Don't write to rlogins (useful if the swap server is down)."},
  79.     {OPT_FALSE, "C", (Address)&consoles,
  80.      "Don't write to consoles (useful just for debugging."},
  81. };
  82.  
  83. /*
  84.  *----------------------------------------------------------------------
  85.  *
  86.  * main --
  87.  *
  88.  *    Prompts the invoker for a message, and then prints the
  89.  *      message to the /dev/syslog of all sprite machines.
  90.  *
  91.  * Results:
  92.  *    Zero exit code if there are no errors.
  93.  *
  94.  * Side effects:
  95.  *    Print a message to everybody's /dev/syslog.
  96.  *
  97.  *----------------------------------------------------------------------
  98.  */
  99.  
  100. void
  101. main(argc, argv)
  102.     int argc;
  103.     char **argv;
  104. {
  105.     register int n;
  106.     register Mig_Info *infoPtr;
  107.     register Host_Entry *hostPtr;
  108.     register char *b;
  109.     register int r;
  110.     register int size;
  111.     register int numRecs;
  112.     int doPrompt;
  113.     int loopIndex;
  114.     int myID;
  115.  
  116.     (void) Opt_Parse(argc, argv, optionArray, Opt_Number(optionArray),
  117.              OPT_ALLOW_CLUSTERING);
  118.  
  119.     FillAlert();
  120.     if ((numRecs = Mig_GetAllInfo(infoArray, MAX_NUM_HOSTS)) <= 0) {
  121.     perror("Error in Mig_GetAllInfo");
  122.     exit(1);
  123.     }
  124.     if ((doPrompt = isatty(0)) != 0) {
  125.     Prompt();
  126.     }
  127.     for (b = buf, size = sizeof(buf); (r = read(0, b, size)) > 0; b += r) {
  128.     if ((size -= r) == 0) {
  129.         (void) fprintf(stderr, "WARNING: max message length exceeded\n");
  130.         break;
  131.     }
  132.     /*
  133.      * stop if a `.' appears at the beginning of a line.
  134.      * This assumes that stdin is line buffered.
  135.      */
  136.     if (*b == '.' && b[-1] == '\n') {
  137.         break;
  138.     }
  139.     if (doPrompt) {
  140.         Prompt();
  141.     }
  142.     }
  143.     size = sizeof(buf) - size;
  144.     if (local) {
  145.     (void) Proc_GetHostIDs(&myID, (int *) NULL);
  146.     }
  147.     for (loopIndex = !consoles; loopIndex <= wallRlogins; loopIndex++) {
  148.     for (n = 0, infoPtr = &infoArray[0]; n < numRecs; ++infoPtr, ++n) {
  149.         if (infoPtr->loadVec.timestamp == 0) {
  150.         continue;
  151.         }
  152.         if (local && infoPtr->hostID != myID) {
  153.         continue;
  154.         }
  155.         if (infoPtr->state == MIG_HOST_DOWN) {
  156.         if (verbose) {
  157.             Down(infoPtr->hostID);
  158.         }
  159.         continue;
  160.         }
  161.         if (infoPtr->loadVec.timestamp - infoPtr->bootTime < 0) {
  162.         if (verbose) {
  163.             Down(infoPtr->hostID);
  164.         }
  165.         continue;
  166.         }
  167.         if ((hostPtr = Host_ByID(infoPtr->hostID)) == NULL) {
  168.         (void) fprintf(stderr, "Error in Host_ByID(%d)\n", infoPtr->hostID);
  169.         continue;
  170.         }
  171.         SendMsg(buf, size, hostPtr->name, loopIndex);
  172.     }
  173.     }
  174.     exit(0);
  175. }   /* main */
  176.  
  177.  
  178. /*
  179.  *----------------------------------------------------------------------
  180.  *
  181.  * Down --
  182.  *
  183.  *      Print a list of all machines that are down.
  184.  *
  185.  * Results:
  186.  *      None.
  187.  * 
  188.  * Side effects:
  189.  *      Prints a list to stdout.
  190.  *  
  191.  *----------------------------------------------------------------------
  192.  */ 
  193.  
  194. static void
  195. Down(n)
  196.     int n;
  197. {
  198.     Host_Entry *hostPtr;
  199.  
  200.     if ((hostPtr = Host_ByID(n)) == NULL) {
  201.     (void) fprintf(stderr, "Error in Host_ByID(%d)\n", n);
  202.     return;
  203.     }
  204.     (void) printf("%s is down\n", hostPtr->name);
  205. }
  206.  
  207.  
  208. /*
  209.  * Set the default timeout, in seconds.
  210.  */
  211. #ifndef TIMEOUT
  212. #define TIMEOUT 10
  213. #endif /* TIMEOUT */
  214. char currentFile[0x400];
  215. int exited;
  216. static jmp_buf    OpenTimeout;
  217.  
  218.  
  219. /*
  220.  *----------------------------------------------------------------------
  221.  *
  222.  * AlarmHandler --
  223.  *
  224.  *    Routine to service a SIGALRM signal.  This routine disables
  225.  *    the alarm (letting the caller reenable it when appropriate).
  226.  *
  227.  * Results:
  228.  *    None.
  229.  *
  230.  * Side effects:
  231.  *    The alarm is disabled, and a warning message is printed. A
  232.  *     global variable is set to indicate that the parent should give up.
  233.  *
  234.  *----------------------------------------------------------------------
  235.  */
  236. static int
  237. AlarmHandler()
  238. {
  239.     exited = 1;
  240.     alarm(0);
  241.     fprintf(stderr, "Warning: couldn't write to %s; removing file.\n",
  242.         currentFile);
  243.     fflush(stderr);
  244.     if (unlink(currentFile) < 0) {
  245.     perror("unlink");
  246.     }
  247.     (void) signal (SIGALRM, SIG_IGN);
  248.     longjmp(OpenTimeout, 1);
  249. }
  250.  
  251. /*
  252.  *----------------------------------------------------------------------
  253.  *
  254.  * SendMsg --
  255.  *
  256.  *      Write the message to a specific host.
  257.  *
  258.  * Results:
  259.  *      None.
  260.  * 
  261.  * Side effects:
  262.  *      Writes the message to the /dev/syslog of the specified host.
  263.  *  
  264.  *----------------------------------------------------------------------
  265.  */ 
  266.  
  267. static void
  268. SendMsg(msg, msize, host, doRlogin)
  269.     char *msg;
  270.     int msize;
  271.     char *host;
  272.     int doRlogin;
  273. {
  274.     int fd;
  275.     int i;
  276.     struct stat statBuf;
  277.     char *s = currentFile;
  278.     int pid;
  279.     
  280.  
  281.     if (!doRlogin) {
  282.     (void) sprintf(s, "/hosts/%s/dev/syslog", host);
  283.     if (debug) {
  284.         printf("would write to %s\n", s);
  285.         return;
  286.     } 
  287.     fd = open(s, O_WRONLY);
  288.     if (fd < 0) {
  289.         perror(s);
  290.         return;
  291.     }
  292.     if (verbose) {
  293.         (void) printf("sending to %s\n", host);
  294.     }
  295.     (void) write(fd, alert, strlen(alert));
  296.     (void) write(fd, msg, msize);
  297.     (void) write(fd, "\7\7\7", 3);
  298.     (void) close(fd);
  299.     } else {
  300.     for (i = 1; i < ULOG_MAX_PORTS; ++i) {
  301.         (void) sprintf(s, "/hosts/%s/%s%d", host, RLOGIN_PDEV_NAME, i);
  302.         if (debug) {
  303.         printf("would write to %s\n", s);
  304.         return;
  305.         } 
  306.         if (stat(s, &statBuf) < 0) {
  307.         continue;
  308.         }
  309.         pid = fork();
  310.         if (pid) {
  311.         union wait status;
  312.         int error;
  313.         int exitCode;
  314.         struct itimerval itimer;
  315.  
  316.         itimer.it_interval.tv_sec = 0;
  317.         itimer.it_interval.tv_usec = 0;
  318.         itimer.it_value.tv_sec = TIMEOUT;
  319.         itimer.it_value.tv_usec = 0;
  320.         (void) signal(SIGALRM, AlarmHandler);
  321.         (void) setitimer(ITIMER_REAL, &itimer, NULL);
  322.  
  323.         exited = 0;
  324.         do {
  325.             if (setjmp(OpenTimeout) != 0) {
  326.             break;
  327.             }
  328.             error = wait(&status);
  329.             if (error == -1) {
  330.             if (errno == EINTR) {
  331.                 /*
  332.                  * This will unfortunately never be reached
  333.                  * until wait can actually return EINTR (not
  334.                  * possible now due to migration interactions
  335.                  * with signals).  Hence the setjmp.
  336.                  */
  337.                 break;
  338.             } else {
  339.                 perror("wait");
  340.                 exited = 1;
  341.             }
  342.             } else if (error == pid) {
  343.             if (status.w_stopval != WSTOPPED) {
  344.                 exited = 1;
  345.             }
  346.             }
  347.         } while (!exited);
  348.         itimer.it_value.tv_sec = 0;
  349.         (void) setitimer(ITIMER_REAL, &itimer, NULL);
  350.         } else {
  351.         /*
  352.          * Child.
  353.          */
  354.         if (verbose) {
  355.             (void) printf("Opening %s.\n", s);
  356.         }
  357.         fd = open(s, O_WRONLY | O_APPEND);
  358.         if (fd < 0) {
  359.             exit(1);
  360.         }
  361.         if (verbose) {
  362.             (void) printf("Writing to %s.\n", s);
  363.         }
  364.         if (write(fd, alert, strlen(alert)) < 0) {
  365.             exit(1);
  366.         }
  367.         (void) write(fd, msg, msize);
  368.         (void) write(fd, "\7\7\7", 3);
  369.         (void) close(fd);
  370.         exit(0);
  371.         } 
  372.         
  373.     }
  374.     }
  375.     return;
  376. }
  377.  
  378.  
  379. /*
  380.  *----------------------------------------------------------------------
  381.  *
  382.  * FillAlert --
  383.  *
  384.  *      Creates the `alert' message that is sent as a prelude
  385.  *      to the main message.
  386.  *
  387.  * Results:
  388.  *      None.
  389.  * 
  390.  * Side effects:
  391.  *      Prints a string into the `alert' buffer.
  392.  *  
  393.  *----------------------------------------------------------------------
  394.  */ 
  395.  
  396. static void
  397. FillAlert()
  398. {
  399.     char *me;
  400.     char hostname[32];
  401.     long clock;
  402.     char *timestamp;
  403. #ifdef notdef
  404.     struct tm *localtime();
  405.     struct tm *localclock;
  406. #endif
  407.     char *ttyname();
  408.  
  409.     me = getpwuid(getuid())->pw_name;
  410.     (void) gethostname(hostname, sizeof(hostname));
  411.     (void) time(&clock);
  412.     timestamp = ctime(&clock);
  413. #ifdef notdef
  414.     localclock = localtime(&clock);
  415.     (void) sprintf(alert,
  416.     "\7\7\7%s broadcast message from %s@%s at %d:%02d ...\n",
  417.     local ? "Local" : "Network-wide", me, hostname,
  418.            localclock->tm_hour, localclock->tm_min);
  419. #endif
  420.     (void) sprintf(alert,
  421.     "\7\7\7%s broadcast message from %s@%s at %s ...\n",
  422.     local ? "Local" : "Network-wide", me, hostname, timestamp);
  423.     return;
  424. }
  425.  
  426.  
  427. /*
  428.  *----------------------------------------------------------------------
  429.  *
  430.  * Prompt --
  431.  *
  432.  *      Print a prompt.
  433.  *
  434.  * Results:
  435.  *      None.
  436.  * 
  437.  * Side effects:
  438.  *      Prints a prompt to stdout.
  439.  *  
  440.  *----------------------------------------------------------------------
  441.  */ 
  442.  
  443. static void
  444. Prompt()
  445. {
  446.  
  447.     (void) write(1, "> ", 2);
  448.     return;
  449. }
  450.  
  451.